import tensorflow as tf

# 张量合并：concat合并不会创建新的维度，stack合并会创建新的维度
a = tf.random.normal([4, 35, 8])
b = tf.random.normal([6, 35, 8])
# 使用concat在第0维合并连个张量
c = tf.concat([a, b], axis=0)

a = tf.random.normal([10, 35, 4])
b = tf.random.normal([10, 35, 4])
# 使用concat在第2维合并连个张量
c = tf.concat([a, b], axis=2)

a = tf.random.normal([35, 8])
b = tf.random.normal([35, 8])
# 使用stack合并在最前面添加维度
c = tf.stack([a, b], axis=0)
print(c.shape)

# 张量分割
x = tf.random.normal([10, 35, 8])
split_result = tf.split(x, num_or_size_splits=10, axis=0)
print(len(split_result))
# 查看切割后单个张量的形状
print(split_result[0].shape)
# 按列表去切割
split_result = tf.split(x, num_or_size_splits=[2, 2, 2, 4], axis=0)
print(split_result[0].shape)
# 如果希望在一个维度上切割固定长度1时，可以使用unstack方法,但是被切割哪一个维度会消失
split_result = tf.unstack(x, axis=0)
print(split_result[0].shape)

# 向量范数
# L1范数：向量x的所有元素绝对值之和
# L2范数：向量x的所有元素平方和开根号
# ∞−范数：向量x的所有元素绝对值的最大值
x = tf.ones([2, 2])
# ord 取 1 2 np.inf 分别代表求L1  L2 ∞ 范数
tf.norm(x, ord=1)

# 最值、均值、和,
x = tf.random.normal([4, 5])
print(x)
# 求维度1上的最大值
max = tf.reduce_max(x, axis=1)
print('max：', max)
# 求维度1上的最小值
min = tf.reduce_min(x, axis=1)
print('min：', min)
# 求维度1上的均值
mean = tf.reduce_mean(x, axis=1)
print('mean：', mean)
# 求维度1上的和
sum = tf.reduce_sum(x, axis=1)
print('sum：', sum)

# 当不指定axis时，就是求的全局元素的最大、最小、均值、和
sum = tf.reduce_sum(x)

# 获取最值的索引
x = tf.random.normal([4, 5])
max = tf.argmax(x, axis=1)
min = tf.argmin(x, axis=1)

# 张量比较
a = tf.constant([1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 6, 4, 3, 2, 4, 0])
b = tf.constant([1, 0, 3, 4, 6, 9, 7, 7, 8, 0, 6, 4, 3, 4, 2, 0])
# 比较两个张量是否相等
c = tf.equal(a, b)
print('张量比较', c)
out = tf.cast(c, dtype=tf.int32)  # 布尔型转为int型
correct = tf.reduce_sum(out)  # 统计True的个数
print('out', out)
print('correct', correct)

# 类似的还有以下比较方法
# tf.math.greater 𝑎>𝑏
# tf.math.less 𝑎<𝑏
# tf.math.greater_equal  𝑎≥𝑏
# tf.math.less_equal  𝑎≤𝑏
# tf.math.not_equal  𝑎≠𝑏
# tf.math.is_nan 𝑎 = nan


# 张量填充，填充规则：[[1,1],[0,1],[1,0]] ：
# 在第一个维度左右填充一个单位，
# 在第二个维度左边不填充右边填充一个单位，
# 在第三个维度左边填充一个单位右边不填充
a = tf.constant([1, 2, 3, 4, 5, 6])  # 第一个句子
b = tf.constant([7, 8, 1, 6])  # 第二个句子
b = tf.pad(b, [[0, 2]])  # 句子末尾填充 2 个 0

# 张量复制 tile
x = tf.random.normal([4, 32, 32, 3])
a = tf.tile(x, [2, 3, 3, 1])  # 数据复制
print(a.shape)  # shape 应该为[8,96,96,3]

# 数据限幅
# 通过 maximum minimum 可以同时对数据的上下编辑限幅
x = tf.range(9)
y = tf.range(9)
tf.maximum(x, 2)  # 向下限幅到2
tf.minimum(y, 7)  # 向上限幅到7

tf.minimum(tf.maximum(x, 2), 7)  # 限幅到2-7
# 通过clip_by_value直接限幅
tf.clip_by_value(x, 2, 7)  # 限幅到2-7
